package com.wish233.wiliwilivideo.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Sets;
import com.wish233.wiliwilivideo.domain.po.Likes;
import com.wish233.wiliwilivideo.service.LikesService;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import static com.wish233.wiliwilicommon.constants.RedisConstants.LIKE_SET_KEY;

/**
 * @author WHH
 * 点赞兜底策略，每天两点扫描Redis和数据库做一个对账
 */
@Service
public class LikeScan {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private LikesService likesService;

    @Scheduled(cron = "0 0 2 * * ?")
    public void scanLike2Database() {
        //从Redis扫描出来和数据库有差异的部分进行兜底处理
        //先扫描出Redis所有的点赞数据
        try (Cursor<String> scan = stringRedisTemplate.scan(ScanOptions.scanOptions()
                .match(LIKE_SET_KEY + "*")
                .build())) {
            while (scan.hasNext()) {
                String key = scan.next();
                // 从Redis获取点赞用户集合
                Set<String> redisIds = stringRedisTemplate.opsForSet().members(key);
                // 解析bizId和messageId
                String[] parts = key.split(":");
                Long bizId = Long.parseLong(parts[1]);
                Long messageId = Long.parseLong(parts[2]);
                // 从数据库获取点赞用户集合
                Set<String> dbIds = new HashSet<>(likesService.list(new QueryWrapper<Likes>()
                        .eq("biz_id", bizId)
                        .eq("message_id", messageId)))
                        .stream()
                        .map(likes -> String.valueOf(likes.getUserId()))
                        .collect(Collectors.toSet());
                // 比对差异
                Set<String> difference = new HashSet<>(Sets.difference(redisIds, dbIds));
                // 将差异数据写入数据库
                if (!difference.isEmpty()) {
                    //将difference构造为Like的List
                    likesService.saveBatch(
                            difference.stream().map(userId -> {
                                        Likes likes = new Likes();
                                        likes.setUserId(Long.valueOf(userId));
                                        likes.setBizId(Math.toIntExact(bizId));
                                        likes.setMessageId(messageId);
                                        return likes;
                                    })
                                    .collect(Collectors.toList())
                    );
                }
            }
        }
    }

}
